﻿namespace System.ServiceModel.DomainServices.EntityFramework
{
    using System;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Data;
    using System.Data.Common;
    using System.Data.Metadata.Edm;
    using System.Data.Objects;
    using System.Linq;
    using System.ServiceModel.DomainServices.Server;

    internal static class ObjectContextUtilities
    {
        public static ObjectStateEntry AttachAsModifiedInternal<T>(T current, T original, ObjectContext objectContext)
        {
            ObjectStateEntry objectStateEntry = objectContext.ObjectStateManager.GetObjectStateEntry(current);
            objectStateEntry.ApplyOriginalValues(original);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
            bool flag = TypeDescriptor.GetAttributes(typeof(T))[typeof(RoundtripOriginalAttribute)] != null;
            foreach (FieldMetadata metadata in objectStateEntry.CurrentValues.DataRecordInfo.FieldMetadata)
            {
                string name = objectStateEntry.CurrentValues.GetName(metadata.Ordinal);
                PropertyDescriptor descriptor = properties[name];
                if (((descriptor != null) && (descriptor.Attributes[typeof(RoundtripOriginalAttribute)] == null)) && (!flag && (descriptor.Attributes[typeof(ExcludeAttribute)] == null)))
                {
                    objectStateEntry.SetModifiedProperty(name);
                }
            }
            return objectStateEntry;
        }

        public static StructuralType GetEdmType(MetadataWorkspace workspace, Type clrType)
        {
            if (workspace == null)
            {
                throw new ArgumentNullException("workspace");
            }
            if (clrType == null)
            {
                throw new ArgumentNullException("clrType");
            }
            if (clrType.IsPrimitive || (clrType == typeof(object)))
            {
                return null;
            }
            EdmType type = null;
            do
            {
                if (!workspace.TryGetType(clrType.Name, clrType.Namespace, DataSpace.OSpace, out type))
                {
                    workspace.LoadFromAssembly(clrType.Assembly);
                    workspace.TryGetType(clrType.Name, clrType.Namespace, DataSpace.OSpace, out type);
                }
            }
            while (((type == null) && ((clrType = clrType.BaseType) != typeof(object))) && (clrType != null));
            StructuralType edmSpaceType = null;
            if ((type != null) && ((type.BuiltInTypeKind == BuiltInTypeKind.EntityType) || (type.BuiltInTypeKind == BuiltInTypeKind.ComplexType)))
            {
                workspace.TryGetEdmSpaceType((StructuralType) type, out edmSpaceType);
            }
            return edmSpaceType;
        }

        public static EntityState GetEntityState(ObjectContext context, object entity)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            ObjectStateEntry entry = null;
            if (!context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry))
            {
                return EntityState.Detached;
            }
            return entry.State;
        }

        public static MetadataProperty GetStoreGeneratedPattern(EdmMember member)
        {
            MetadataProperty property;
            member.MetadataProperties.TryGetValue("http://schemas.microsoft.com/ado/2009/02/edm/annotation:StoreGeneratedPattern", true, out property);
            return property;
        }

        public static bool IsConcurrencyTimestamp(EdmMember member)
        {
            Facet facet = member.TypeUsage.Facets.SingleOrDefault<Facet>(p => p.Name == "ConcurrencyMode");
            if (((facet == null) || (facet.Value == null)) || (((ConcurrencyMode) facet.Value) != ConcurrencyMode.Fixed))
            {
                return false;
            }
            facet = member.TypeUsage.Facets.SingleOrDefault<Facet>(p => p.Name == "FixedLength");
            if (((facet == null) || (facet.Value == null)) || !((bool) facet.Value))
            {
                return false;
            }
            facet = member.TypeUsage.Facets.SingleOrDefault<Facet>(p => p.Name == "MaxLength");
            if (((facet == null) || (facet.Value == null)) || (((int) facet.Value) != 8))
            {
                return false;
            }
            MetadataProperty storeGeneratedPattern = GetStoreGeneratedPattern(member);
            return (((storeGeneratedPattern != null) && (facet.Value != null)) && !(((string) storeGeneratedPattern.Value) != "Computed"));
        }
    }
}

